package com.itheima.wemedia.service.impl;

import com.alibaba.fastjson.JSON;
import com.alibaba.nacos.api.config.filter.IFilterConfig;
import com.baomidou.mybatisplus.core.conditions.Wrapper;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;

import com.baomidou.mybatisplus.core.toolkit.CollectionUtils;
import com.baomidou.mybatisplus.core.toolkit.StringUtils;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.itheima.common.constants.BusinessConstants;
import com.itheima.common.exception.LeadNewsException;
import com.itheima.common.util.RequestContextUtil;
import com.itheima.common.vo.PageResultVo;
import com.itheima.wemedia.dto.WmNewsContentNodeDto;
import com.itheima.wemedia.dto.WmNewsDtoSave;
import com.itheima.wemedia.dto.WmNewsPageReqDto;
import com.itheima.wemedia.mapper.WmMaterialMapper;
import com.itheima.wemedia.mapper.WmNewsMapper;
import com.itheima.wemedia.mapper.WmNewsMaterialMapper;
import com.itheima.wemedia.pojo.WmMaterial;
import com.itheima.wemedia.pojo.WmNews;
import com.itheima.wemedia.pojo.WmNewsMaterial;
import com.itheima.wemedia.service.WmNewsService;
import org.apache.commons.io.CopyUtils;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.kafka.core.KafkaTemplate;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.time.LocalDateTime;
import java.util.*;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import java.util.stream.Collectors;

/**
 * @description <p>自媒体图文内容信息 业务实现</p>
 *
 * @version 1.0
 * @package com.itheima.wemedia.service.impl
 */
@Service
public class WmNewsServiceImpl extends ServiceImpl<WmNewsMapper, WmNews> implements WmNewsService {

    @Autowired
    private WmNewsMaterialMapper wmNewsMaterialMapper;

    @Autowired
    private KafkaTemplate kafkaTemplate;

    @Autowired
    private WmMaterialMapper wmMaterialMapper;
    /**
     * 分页查询
     * @param wq
     * @return
     */
    @Override
    public PageResultVo<WmNews> findPage(WmNewsPageReqDto wq) {

        //1.设置分页参数
        IPage<WmNews>  pageInfo = new Page<>(wq.getPage(),wq.getSize());
        //2.构建分页条件
        LambdaQueryWrapper<WmNews>  lqw = Wrappers.<WmNews>lambdaQuery()
                .eq(null!=wq.getStatus(),WmNews::getStatus,wq.getStatus())
                .eq(null!=wq.getChannelId(),WmNews::getChannelId,wq.getChannelId())
                .eq(WmNews::getUserId, RequestContextUtil.getUserId())
                .eq(null!=wq.getBeginPubDate(),WmNews::getPublishTime,wq.getBeginPubDate())
                .lt(null!=wq.getEndPubDate(),WmNews::getPublishTime,wq.getEndPubDate())
                .like(null!=wq.getKeyword(),WmNews::getTitle,wq.getKeyword())
                .orderByDesc(WmNews::getCreatedTime);
        //3.分页查询
        IPage<WmNews> page1 = page(pageInfo, lqw);

        //4.构建分页结构并返回
        return PageResultVo.pageResult(wq.getPage(), wq.getSize(),page1.getTotal(),page1.getRecords() );

    }

    /**
     * 发布文章
     * @param draft
     * @param dto
     * @return
     */
    @Override
    @Transactional
    public Integer submit(boolean draft, WmNewsDtoSave dto) {

        if(null == dto|| StringUtils.isEmpty(dto.getContent())){
            throw new LeadNewsException("文章内容不能为空!");

        }
        //1.发布前端发过来的参数
        //接收封面图片
        List<String> coverList = new ArrayList<>();

        //2.构建WmNews对象
        WmNews pojo = new WmNews();
        BeanUtils.copyProperties(dto,pojo);
        pojo.setContent(dto.getContent());
        pojo.setUserId(Integer.parseInt(RequestContextUtil.getUserId()));
        pojo.setStatus(draft?0:1);
        if (!CollectionUtils.isEmpty(dto.getImages())){
            pojo.setImages(String.join(",", dto.getImages()));
            coverList.addAll(dto.getImages());
        }
        //3.发布文章布局类型，设置图片
        List<WmNewsContentNodeDto> contentList = JSON.parseArray(dto.getContent(), WmNewsContentNodeDto.class);
        //4.获取内容中的图片
        List<String> imageList = contentList.stream().filter(cn -> BusinessConstants.WmNewsConstants.CONTENT_IMAGE.equals(cn.getType()))
                .map(WmNewsContentNodeDto::getValue).collect(Collectors.toList());

        if (BusinessConstants.WmNewsConstants.TYPE_AUTO == dto.getType().intValue()){
            int size = imageList.size();
            coverList= new ArrayList<String>();
            if (size>2){
                pojo.setType(BusinessConstants.WmNewsConstants.TYPE_SINGLE_IMG);
                pojo.setImages("");
            }
        }

        //5.保存文章到数据库\\
        // - 判断是否存在id，不存在则添加到文章表
        if (null == dto.getId()){
                pojo.setCreatedTime(LocalDateTime.now());
                getBaseMapper().insert(pojo);

        }else {
            //   - 如果存在，则更新文章表，并且要删除文章与素材的关系
            getBaseMapper().updateById(pojo);
            wmNewsMaterialMapper.delete(new LambdaQueryWrapper<WmNewsMaterial>().eq(WmNewsMaterial::getNewsId,dto.getId()));


        }
        //6.添加文章与素材的关系
        saveWmNewsMaterialRelationship(pojo.getId(),coverList,imageList);
        //7.添加事务控制
        //返回新增文章id

        //8.0文章的自动审核，kafka生产者
        //8.1 判断如果是提交审核，就发送给kafka，到admin那边，消费者接受
        if (pojo.getStatus() ==BusinessConstants.WmNewsConstants.STATUS_SUBMIT){

            kafkaTemplate.send(BusinessConstants.MqConstants.WM_NEWS_AUTO_SCAN_TOPIC,pojo.getId().toString());
        }
        
        return pojo.getId();
    }

    /**
     * 根据id删除，判断是否已经上架了
     * @param newdele_id
     */
    @Override
    @Transactional
    public void deleteById(int newdele_id) {

        //1.通过id查询
        //2. 如果状态是为已发布或已上架，则不能删除
        WmNews wmNews = getById(newdele_id);
        if (wmNews.getStatus()  == BusinessConstants.WmNewsConstants.STATUS_PUBLISHED
          || wmNews.getEnable() ==  BusinessConstants.WmNewsConstants.ENABLE_ON
        ){
            throw new LeadNewsException("文章已经上架，不能删除");
        }
        // 3.否则可以删除
       removeById(newdele_id);
        //4.删除后同步删除文章和素材的关系
        wmNewsMaterialMapper.delete(Wrappers.<WmNewsMaterial>lambdaQuery()
                .eq(WmNewsMaterial::getNewsId,newdele_id));
    }

    /**
     * 添加文章与图片的关系
     * @param newsId
     * @param coverImageList
     * @param contentImageList
     */
    private void saveWmNewsMaterialRelationship(Integer newsId, List<String> coverImageList, List<String> contentImageList) {
        // 合并图片集合且去重
        Set<String> allImages = new HashSet<String>();
        if(CollectionUtils.isNotEmpty(coverImageList)){
            // 去除集合中每个图片地址中的前缀
            coverImageList = coverImageList.stream().map(this::removePrefix).collect(Collectors.toList());
            allImages.addAll(coverImageList);
        }
        // 内容中的图片处理
        if(CollectionUtils.isNotEmpty(contentImageList)){
            // 图片地址截取去掉前缀，得到FileID
            contentImageList = contentImageList.stream().map(this::removePrefix).collect(Collectors.toList());
            allImages.addAll(contentImageList);
        }
        // 通过FileID查询素材表获取素材表中的id
        if(CollectionUtils.isNotEmpty(allImages)) {
            // 构建批量查询条件
            LambdaQueryWrapper<WmMaterial> queryWrapper = Wrappers.<WmMaterial>lambdaQuery().in(WmMaterial::getUrl, allImages);
            // 通过url批量查询 allImages.size=3,  wmMaterials.size()=2
            List<WmMaterial> wmMaterials = wmMaterialMapper.selectList(queryWrapper);
            if(null==wmMaterials || allImages.size() != wmMaterials.size()){
                throw new LeadNewsException("文章素材缺失");
            }
            // 添加素材(id,url)与文章的关系
            Map<String, Integer> urlIdMap = wmMaterials.stream().collect(Collectors.toMap(WmMaterial::getUrl, WmMaterial::getId));
            // 相当于上面的一句话
            /*Map<String, Integer> map = new HashMap<>();
            for (WmMaterial wmMaterial : wmMaterials) {
                map.put(wmMaterial.getUrl(), wmMaterial.getId());
            }*/

            // map<url,id> map.get(url) -> id
            // 1. 封面 url, 转成WmNewsMaterial对象(newsId, 素材id,1)
            if(CollectionUtils.isNotEmpty(coverImageList)){
                for (String url : coverImageList) {
                    // 获取素材的id
                    Integer materialId = urlIdMap.get(url);
                    WmNewsMaterial newsMaterial = new WmNewsMaterial();
                    newsMaterial.setMaterialId(materialId);
                    newsMaterial.setNewsId(newsId);
                    newsMaterial.setType(BusinessConstants.WmNewsConstants.WM_COVER_REFERENCE);
                    wmNewsMaterialMapper.insert(newsMaterial);
                }
            }
            // 2. 内容 url 转成WmNewsMaterial对象(newsId, 素材id,0)
            if(CollectionUtils.isNotEmpty(contentImageList)){
                for (String url : contentImageList) {
                    // 获取素材的id
                    Integer materialId = urlIdMap.get(url);
                    WmNewsMaterial newsMaterial = new WmNewsMaterial();
                    newsMaterial.setMaterialId(materialId);
                    newsMaterial.setNewsId(newsId);
                    newsMaterial.setType(BusinessConstants.WmNewsConstants.WM_CONTENT_REFERENCE);
                    wmNewsMaterialMapper.insert(newsMaterial);
                }
            }
            //mybatis批量添加
        }
    }

    private String removePrefix(String url){
        return url.replaceAll("http://((\\d){1,3}\\.){3}(\\d){1,3}:?(\\d){0,5}\\/", "");
    }

    public static void main(String[] args) {
        String imageUrl = "http://192.168.211.128/group1/M00/00/00/wKjTgGJjqGmAZPsKAACWAYXFQc8970.jpg";
        Pattern p = Pattern.compile("http://((\\d){1,3}\\.){3}(\\d){1,3}:?(\\d){0,5}\\/");
        Matcher matcher = p.matcher(imageUrl);
        System.out.println(matcher.find());
        System.out.println(matcher.replaceAll(""));

    }
    /**
     * 文章的上架和下架
     * @param paramsMap
     */
    @Override
    public void downUp(Map<String, Integer> paramsMap) {
        //1.获取前端的参数
        Integer News_id = paramsMap.get("id");
        Integer enable = paramsMap.get("enable");

        //1.1判断不能为空
        if (News_id == null || enable ==null || enable.intValue()<0 || enable.intValue()>1 ){
            throw  new LeadNewsException("参数有误");
        }

        //2.通过前端id查询参数
        WmNews news = getById(News_id);
        //3.文章状态判断，只有发布的文章才能进行上下架操作
        if (news.getStatus().intValue() != BusinessConstants.WmNewsConstants.STATUS_BLOCK){
            throw  new LeadNewsException("文章未发布，不能上架或下架操作");

        }

        //4.构建pojo
        WmNews pojo = new WmNews();
        pojo.setId(News_id);
        pojo.setEnable(enable);
        //5.通过id更新
        updateById(pojo);
    }


}


    /**
     * 保存文章与素材的关系
     * @param coverList
     * @param newsId
     * @param imageList
     *//*
    private void saveRelationship(List<String> coverList, Integer newsId, List<String> imageList) {

        //5.1查询出文章对应的id
        List<String> alliImagesList =  new  ArrayList<>();
        alliImagesList.addAll(imageList);
        alliImagesList.addAll(coverList);
        if (alliImagesList.size()>0){
            //5.2通过url批量查询所有素材信息
            List<WmMaterial> wmMaterials = wmMaterialMapper.selectList(Wrappers.<WmMaterial>lambdaQuery().in(WmMaterial::getUrl, alliImagesList));
            if (CollectionUtils.isEmpty(wmMaterials)){
                throw new LeadNewsException("招不到相关素材");
            }

            //key为url value 为 id
            // key为url, value为id
            Map<String, Integer> materialMap = wmMaterials.stream().collect(Collectors.toMap(WmMaterial::getUrl, WmMaterial::getId));
            if (!alliImagesList.stream().allMatch(s->null!=materialMap.get(s))) {
                throw new LeadNewsException("查找不到相关素材!");
            }
            // 构建要保存的对象, 分两类：内容素材与封面素材，因为一张图片素材即可能是内容，也可能是封面
            List<WmNewsMaterial> newsMaterials2Add = new ArrayList<>();
            // 构建内容素材
            List<WmNewsMaterial> contentMaterials = imageList.stream().map(url -> WmNewsMaterial.build(materialMap.get(url), newsId, BusinessConstants.WmNewsConstants.WM_CONTENT_REFERENCE)).collect(Collectors.toList());
            newsMaterials2Add.addAll(contentMaterials);
            // 构建封面素材
            if(coverList.size() > 0){
                List<WmNewsMaterial> coverMaterials = coverList.stream().map(url -> WmNewsMaterial.build(materialMap.get(url), newsId, BusinessConstants.WmNewsConstants.WM_COVER_REFERENCE)).collect(Collectors.toList());
                newsMaterials2Add.addAll(coverMaterials);
                //5.3批量添加文章与素材关系
          wmNewsMaterialMapper.insertBatch(newsMaterials2Add);

    }*/

